﻿using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using LinqtoCRM.Tests.CRM;

namespace LinqtoCRM.Tests
{
    [TestFixture]
    public class QueryTestsWithNewSelector : LinqtoCRMTests
    {

        [Test]
        public void TestAllContactsQuery()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><attribute name=\"contactid\" /><attribute name=\"firstname\" /></entity></fetch>";
            var contacts = from c in provider.Linq<contact>()
                           select new { c.contactid, c.firstname };
            AssertXmlEquals(expectedXml, contacts);
        }

        [Test]
        public void TestContactIdQuery()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><attribute name=\"contactid\" /></entity></fetch>";
            var contacts = from c in provider.Linq<contact>()
                           select new { c.contactid };
            AssertXmlEquals(expectedXml, contacts);
        }

        [Test]
        public void TestContactsQueryWhere()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><attribute name=\"contactid\" /><attribute name=\"firstname\" /><filter><condition attribute=\"firstname\" operator=\"eq\" value=\"Scott\" /></filter></entity></fetch>";

            var contactsNamedScott = from c in provider.Linq<contact>()
                                     where c.firstname == "Scott"
                                     select new { c.contactid, c.firstname };
            AssertXmlEquals(expectedXml, contactsNamedScott);
        }

        [Test]
        public void TestChainedContactsQuery()
        {
            string expectedXml = @"
                <fetch mapping=""logical"">
                    <entity name=""contact"">
                        <attribute name=""contactid"" />
                        <attribute name=""firstname"" />
                        <filter><condition attribute=""firstname"" operator=""eq"" value=""Scott"" /></filter>
                    </entity>
                </fetch>";
            var contacts = from c in provider.Linq<contact>()
                           select c;
            var contactsNamedScottChained = from c in contacts
                                            where c.firstname == "Scott"
                                            select new { c.contactid, c.firstname };
            AssertXmlEquals(expectedXml, contactsNamedScottChained);
        }

        [Test]
        public void TestDoubleWhere()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><attribute name=\"contactid\" /><attribute name=\"firstname\" /><filter><condition attribute=\"firstname\" operator=\"eq\" value=\"Scott\" /><condition attribute=\"lastname\" operator=\"eq\" value=\"Scott\" /></filter></entity></fetch>";

            var contactsNamedScottScott = from c in provider.Linq<contact>()
                                          where c.firstname == "Scott" && c.lastname == "Scott"
                                          select new { c.contactid, c.firstname };
            AssertXmlEquals(expectedXml, contactsNamedScottScott);
        }

        [Test]
        [Category("StringOperations")]
        public void TestContains()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><attribute name=\"contactid\" /><attribute name=\"firstname\" /><filter><condition attribute=\"firstname\" operator=\"like\" value=\"%Scott%\" /></filter></entity></fetch>";

            var contactsContainingScott = from c in provider.Linq<contact>()
                                          where c.firstname.Contains("Scott")
                                          select new { c.contactid, c.firstname };
            AssertXmlEquals(expectedXml, contactsContainingScott);
        }

        [Test]
        [Category("StringOperations")]
        public void TestStartsWith()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><attribute name=\"contactid\" /><attribute name=\"firstname\" /><filter><condition attribute=\"firstname\" operator=\"like\" value=\"Scott%\" /></filter></entity></fetch>";

            var contactsStartingWithScott = from c in provider.Linq<contact>()
                                            where c.firstname.StartsWith("Scott")
                                            select new { c.contactid, c.firstname };
            AssertXmlEquals(expectedXml, contactsStartingWithScott);
        }

        [Test]
        [Category("StringOperations")]
        public void TestEndsWith()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><attribute name=\"contactid\" /><attribute name=\"firstname\" /><filter><condition attribute=\"firstname\" operator=\"like\" value=\"%Scott\" /></filter></entity></fetch>";

            var contactsEndingWithScott = from c in provider.Linq<contact>()
                                          where c.firstname.EndsWith("Scott")
                                          select new { c.contactid, c.firstname };
            AssertXmlEquals(expectedXml, contactsEndingWithScott);
        }

        [Test]
        [Category("StringOperations")]
        public void TestEquals()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><attribute name=\"contactid\" /><attribute name=\"firstname\" /><filter><condition attribute=\"firstname\" operator=\"like\" value=\"Scott\" /></filter></entity></fetch>";

            var contactsNamedScott = from c in provider.Linq<contact>()
                                     where c.firstname.Equals("Scott")
                                     select new { c.contactid, c.firstname };
            AssertXmlEquals(expectedXml, contactsNamedScott);
        }

        [Test]
        public void TestOr()
        {
            AssertXmlEquals(@"
                <fetch mapping=""logical"">
                  <entity name=""contact"">
                    <attribute name=""firstname"" />
                    <filter type=""or"">
                      <condition attribute=""firstname"" operator=""eq"" value=""Paul"" />
                      <condition attribute=""firstname"" operator=""eq"" value=""Frank"" />
                    </filter>
                  </entity>
                </fetch>",
                from c in provider.Linq<contact>()
                where c.firstname == "Paul" || c.firstname == "Frank"
                select new { c.firstname }
                );
        }

        [Test]
        public void TestComplexOr()
        {
            AssertXmlEquals(@"
                <fetch mapping=""logical"">
                  <entity name=""contact"">
                    <attribute name=""firstname"" />
                    <filter type=""or"">
                      <condition attribute=""firstname"" operator=""eq"" value=""Paul"" />
                      <condition attribute=""address1_country"" operator=""ne"" value=""UK"" />
                      <filter>
                        <condition attribute=""firstname"" operator=""like"" value=""F%"" />
                        <condition attribute=""firstname"" operator=""like"" value=""%k"" />
                      </filter>
                    </filter>
                  </entity>
                </fetch>",
                from c in provider.Linq<contact>()
                where c.firstname == "Paul" || c.address1_country != "UK" || c.firstname.StartsWith("F") && c.firstname.EndsWith("k")
                select new { c.firstname }
            );
        }

        [Test]
        public void TestOrderBy()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><attribute name=\"contactid\" /><attribute name=\"firstname\" /><order attribute=\"firstname\" /></entity></fetch>";
            var contactsOrderedByFirstname = from c in provider.Linq<contact>()
                                             orderby c.firstname
                                             select new { c.contactid, c.firstname };
            AssertXmlEquals(expectedXml, contactsOrderedByFirstname);
        }

        [Test]
        public void TestOrderByDesc()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><attribute name=\"contactid\" /><attribute name=\"firstname\" /><order attribute=\"firstname\" descending=\"true\" /></entity></fetch>";
            var contactsOrderedByFirstname = from c in provider.Linq<contact>()
                                             orderby c.firstname descending
                                             select new { c.contactid, c.firstname };
            AssertXmlEquals(expectedXml, contactsOrderedByFirstname);
        }

        [Test]
        public void TestOrderByWhere()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><attribute name=\"contactid\" /><attribute name=\"firstname\" /><order attribute=\"firstname\" /><filter><condition attribute=\"firstname\" operator=\"eq\" value=\"Scott\" /></filter></entity></fetch>";
            var contactsOrderedByFirstname = from c in provider.Linq<contact>()
                                             orderby c.firstname
                                             where c.firstname == "Scott"
                                             select new { c.contactid, c.firstname };
            AssertXmlEquals(expectedXml, contactsOrderedByFirstname);
        }

        [Test]
        public void TestJoin()
        {
            string expectedXml = @"
                <fetch mapping=""logical"">
                    <entity name=""contact"">
                        <attribute name=""contactid"" />
                        <attribute name=""firstname"" />
                        <link-entity name=""account"" from=""accountid"" to=""parentcustomerid"" />
                    </entity>
                </fetch>";
            var contactsJoinedOnAccounts = from c in provider.Linq<contact>()
                                           join a in provider.Linq<account>()
                                           on c.parentcustomerid.Value equals a.accountid.Value
                                           select new { c.contactid, c.firstname };
            AssertXmlEquals(expectedXml, contactsJoinedOnAccounts);
        }

        [Test]
        public void TestJoinOrderBy()
        {
            string expectedXml = @"
                <fetch mapping=""logical"">
                    <entity name=""contact"">
                        <attribute name=""contactid"" />
                        <attribute name=""firstname"" />
                        <order attribute=""firstname"" />
                        <link-entity name=""account"" from=""accountid"" to=""parentcustomerid"" />
                    </entity>
                </fetch>";
            var contactsJoinedOnAccountsOrdered = from c in provider.Linq<contact>()
                                                  join a in provider.Linq<account>()
                                                  on c.parentcustomerid.Value equals a.accountid.Value
                                                  orderby c.firstname
                                                  select new { c.contactid, c.firstname };
            AssertXmlEquals(expectedXml, contactsJoinedOnAccountsOrdered);
        }


        [Test]
        public void TestJoinWhere()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><attribute name=\"contactid\" /><attribute name=\"firstname\" /><filter><condition attribute=\"firstname\" operator=\"eq\" value=\"Scott\" /></filter><link-entity name=\"account\" from=\"accountid\" to=\"parentcustomerid\" /></entity></fetch>";
            var contactsNamedScottJoinedOnAccounts = from c in provider.Linq<contact>()
                                                     join a in provider.Linq<account>()
                                                     on c.parentcustomerid.Value equals a.accountid.Value
                                                     where c.firstname == "Scott"
                                                     select new { c.contactid, c.firstname };
            AssertXmlEquals(expectedXml, contactsNamedScottJoinedOnAccounts);
        }


        [Test]
        public void TestJoinOrderByWhere()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><attribute name=\"contactid\" /><attribute name=\"firstname\" /><order attribute=\"firstname\" /><filter><condition attribute=\"firstname\" operator=\"eq\" value=\"Scott\" /></filter><link-entity name=\"account\" from=\"accountid\" to=\"parentcustomerid\" /></entity></fetch>";
            var contactsNamedScottJoinedOnAccountsOrdered = from c in provider.Linq<contact>()
                                                            join a in provider.Linq<account>()
                                                            on c.parentcustomerid.Value equals a.accountid.Value
                                                            orderby c.firstname
                                                            where c.firstname == "Scott"
                                                            select new { c.contactid, c.firstname };
            AssertXmlEquals(expectedXml, contactsNamedScottJoinedOnAccountsOrdered);
        }

        [Test]
        public void TestJoinOrderByDoubleWhere()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><attribute name=\"contactid\" /><attribute name=\"firstname\" /><order attribute=\"firstname\" /><filter><condition attribute=\"firstname\" operator=\"eq\" value=\"Scott\" /><condition attribute=\"lastname\" operator=\"eq\" value=\"Scott\" /></filter><link-entity name=\"account\" from=\"accountid\" to=\"parentcustomerid\" /></entity></fetch>";
            var contactsNamedScottScottJoinedOnAccountsOrdered = from c in provider.Linq<contact>()
                                                                 join a in provider.Linq<account>()
                                                                 on c.parentcustomerid.Value equals a.accountid.Value
                                                                 orderby c.firstname
                                                                 where c.firstname == "Scott" && c.lastname == "Scott"
                                                                 select new { c.contactid, c.firstname };
            AssertXmlEquals(expectedXml, contactsNamedScottScottJoinedOnAccountsOrdered);
        }

        [Test]
        public void TestPagingFirstTen()
        {
            string expectedXml = "<fetch mapping=\"logical\" count=\"10\"><entity name=\"contact\"><attribute name=\"contactid\" /><attribute name=\"firstname\" /></entity></fetch>";
            var firstTenContacts = (from c in provider.Linq<contact>()
                                    select new { c.contactid, c.firstname }).Skip(0).Take(10);
            AssertXmlEquals(expectedXml, firstTenContacts);
        }

        [Test]
        public void TestPagingSecondTen()
        {
            string expectedXml = "<fetch mapping=\"logical\" count=\"10\" page=\"2\"><entity name=\"contact\"><attribute name=\"contactid\" /><attribute name=\"firstname\" /></entity></fetch>";
            var secondTenContacts = (from c in provider.Linq<contact>()
                                     select new { c.contactid, c.firstname }).Skip(10).Take(10);
            AssertXmlEquals(expectedXml, secondTenContacts);
        }

        [Test]
        public void TestPagingFirstTenNineSkipped()
        {
            string expectedXml = "<fetch mapping=\"logical\" count=\"10\"><entity name=\"contact\"><attribute name=\"contactid\" /><attribute name=\"firstname\" /></entity></fetch>";
            var firstTenContactsNineSkipped = (from c in provider.Linq<contact>()
                                               select new { c.contactid, c.firstname }).Skip(9).Take(10);
            AssertXmlEquals(expectedXml, firstTenContactsNineSkipped);
        }

        [Test]
        public void TestPagingFirstTenWithWhere()
        {
            string expectedXml = "<fetch mapping=\"logical\" count=\"10\"><entity name=\"contact\"><attribute name=\"contactid\" /><attribute name=\"firstname\" /><filter><condition attribute=\"firstname\" operator=\"eq\" value=\"Scott\" /></filter></entity></fetch>";
            var firstTenContactsNamedScott = (from c in provider.Linq<contact>()
                                              where c.firstname == "Scott"
                                              select new { c.contactid, c.firstname }).Skip(0).Take(10);
            AssertXmlEquals(expectedXml, firstTenContactsNamedScott);
        }

        [Test]
        public void TestPagingFirstTenOrdered()
        {
            string expectedXml = "<fetch mapping=\"logical\" count=\"10\"><entity name=\"contact\"><attribute name=\"contactid\" /><attribute name=\"firstname\" /><order attribute=\"firstname\" /></entity></fetch>";
            var firstTenContactsOrdered = (from c in provider.Linq<contact>()
                                           orderby c.firstname
                                           select new { c.contactid, c.firstname }).Skip(0).Take(10);
            AssertXmlEquals(expectedXml, firstTenContactsOrdered);
        }

        [Test]
        public void TestPagingFirstTenJoined()
        {
            string expectedXml = "<fetch mapping=\"logical\" count=\"10\"><entity name=\"contact\"><attribute name=\"contactid\" /><attribute name=\"firstname\" /><link-entity name=\"account\" from=\"accountid\" to=\"parentcustomerid\" /></entity></fetch>";
            var firstTenContactsJoined = (from c in provider.Linq<contact>()
                                          join a in provider.Linq<account>()
                                          on c.parentcustomerid.Value equals a.accountid.Value
                                          select new { c.contactid, c.firstname }).Skip(0).Take(10);
            AssertXmlEquals(expectedXml, firstTenContactsJoined);
        }

        [Test]
        public void TestOrderByThenBy()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><attribute name=\"contactid\" /><order attribute=\"firstname\" /><order attribute=\"contactid\" /></entity></fetch>";
            var contactsOrderedByFirstname = from c in provider.Linq<contact>()
                                             orderby c.firstname, c.contactid
                                             select new { c.contactid };
            AssertXmlEquals(expectedXml, contactsOrderedByFirstname);
        }

        [Test]
        public void TestOrderByDescendingThenByDescending()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><attribute name=\"contactid\" /><order attribute=\"firstname\" descending=\"true\" /><order attribute=\"contactid\" descending=\"true\" /></entity></fetch>";
            var contactsOrderedByFirstnameDescendingThenByContactidDescending = from c in provider.Linq<contact>()
                                                                                orderby c.firstname descending, c.contactid descending
                                                                                select new { c.contactid };
            AssertXmlEquals(expectedXml, contactsOrderedByFirstnameDescendingThenByContactidDescending);
        }

        [Test]
        public void TestOrderByThenByDescending()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><attribute name=\"contactid\" /><order attribute=\"firstname\" /><order attribute=\"contactid\" descending=\"true\" /></entity></fetch>";
            var contactsOrderedByFirstnameThenByContactidDescending = from c in provider.Linq<contact>()
                                                                      orderby c.firstname, c.contactid descending
                                                                      select new { c.contactid };
            AssertXmlEquals(expectedXml, contactsOrderedByFirstnameThenByContactidDescending);
        }

        [Test]
        public void TestOrderByDescendingThenBy()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><attribute name=\"contactid\" /><order attribute=\"firstname\" descending=\"true\" /><order attribute=\"contactid\" /></entity></fetch>";
            var contactsOrderedByFirstnameDescendingThenByContactid = from c in provider.Linq<contact>()
                                                                      orderby c.firstname descending, c.contactid
                                                                      select new { c.contactid };
            AssertXmlEquals(expectedXml, contactsOrderedByFirstnameDescendingThenByContactid);
        }

        [Test]
        public void TestOrderByThenByThenBy()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><attribute name=\"contactid\" /><order attribute=\"firstname\" /><order attribute=\"lastname\" /><order attribute=\"contactid\" /></entity></fetch>";
            var contactsOrderedByFirstnameLastnameContactid = from c in provider.Linq<contact>()
                                                              orderby c.firstname, c.lastname, c.contactid
                                                              select new { c.contactid };
            AssertXmlEquals(expectedXml, contactsOrderedByFirstnameLastnameContactid);
        }

        [Test]
        public void TestSelectJoinedProperties()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><attribute name=\"firstname\" /><attribute name=\"lastname\" /><link-entity name=\"account\" from=\"accountid\" to=\"parentcustomerid\"><attribute name=\"name\" /></link-entity></entity></fetch>";
            var contactAndAccountInfo = from c in provider.Linq<contact>()
                                        join a in provider.Linq<account>()
                                        on c.parentcustomerid.Value equals a.accountid.Value
                                        select new { c.firstname, c.lastname, a.name };
            AssertXmlEquals(expectedXml, contactAndAccountInfo);
        }

        [Test]
        public void TestSelectAndOrderJoinedProperties()
        {
            string expectedXml = @"
                <fetch mapping=""logical"">
                    <entity name=""contact"">
                        <attribute name=""firstname"" />
                        <attribute name=""lastname"" />
                        <link-entity name=""account"" from=""accountid"" to=""parentcustomerid"">
                            <attribute name=""name"" />
                            <order attribute=""name"" />
                        </link-entity>
                    </entity>
                </fetch>";
            var contactAndAccountInfo = from c in provider.Linq<contact>()
                                        join a in provider.Linq<account>()
                                        on c.parentcustomerid.Value equals a.accountid.Value
                                        orderby a.name
                                        select new { c.firstname, c.lastname, a.name };
            AssertXmlEquals(expectedXml, contactAndAccountInfo);
        }

        /// <summary>
        /// Issue #5390 
        /// Where clauses on linked entity attributes fail
        /// </summary>
        [Test]
        public void TestJoinWhereOnJoinedSelectOther()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><attribute name=\"firstname\" /><attribute name=\"lastname\" /><link-entity name=\"account\" from=\"accountid\" to=\"parentcustomerid\"><attribute name=\"name\" /><filter><condition attribute=\"name\" operator=\"like\" value=\"%Scott%\" /></filter></link-entity></entity></fetch>";
            var contacts = from c in provider.Linq<contact>()
                           join a in provider.Linq<account>()
                           on c.parentcustomerid.Value equals a.accountid.Value
                           where a.name.Contains("Scott")
                           select new { c.firstname, c.lastname, a.name };
            AssertXmlEquals(expectedXml, contacts);
        }

        /// <summary>
        /// steffana
        /// Allowing left joins usings GroupJoin 
        /// </summary>
        [Test]
        public void TestLeftJoin()
        {
            string expectedXml = @"
                <fetch mapping=""logical"">
                    <entity name=""contact"">
                        <attribute name=""fullname"" />
                        <link-entity name=""account"" from=""accountid"" to=""parentcustomerid"" link-type=""outer"">
                            <attribute name=""name"" />
                        </link-entity>
                    </entity>
                </fetch>";
            var contactsJoinedOnAccounts = from c in provider.Linq<contact>()
                                           join a in provider.Linq<account>()
                                            on c.parentcustomerid.Value equals a.accountid.Value into temp
                                           from t in temp.DefaultIfEmpty()
                                           select new { c.fullname, t.name };
            AssertXmlEquals(expectedXml, contactsJoinedOnAccounts);
        }

        /// <summary>
        /// steffana
        /// Select into BusinessEntity - but only specified attributes
        /// Simple
        /// </summary>
        [Test]
        public void TestSelectToBusinessEntity()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><attribute name=\"contactid\" /></entity></fetch>";
            var contacts = from c in provider.Linq<contact>()
                           select new contact { contactid = c.contactid };
            AssertXmlEquals(expectedXml, contacts);
        }

        /// <summary>
        /// Select into BusinessEntity - but only specified attributes
        /// Simple - selecting into BusinessEntity different from the source
        /// </summary>
        [Test]
        public void TestSelectToOtherBusinessEntity()
        {
            string expectedXml = @"
                <fetch mapping=""logical"">
                    <entity name=""contact"">
                        <attribute name=""fullname"" />
                    </entity>
                </fetch>";
            var contacts = from c in provider.Linq<contact>()
                           select new account { name = c.fullname };
            AssertXmlEquals(expectedXml, contacts);
        }

        /// <summary>
        /// steffana
        /// Select into BusinessEntity - but only specified attributes
        /// With join
        /// </summary>
        [Test]
        public void TestJoinSelectToBusinessEntity()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><attribute name=\"fullname\" /><link-entity name=\"account\" from=\"accountid\" to=\"parentcustomerid\" /></entity></fetch>";
            var contacts = from c in provider.Linq<contact>()
                           join a in provider.Linq<account>()
                            on c.parentcustomerid.Value equals a.accountid.Value
                           select new contact { fullname = c.fullname };
            AssertXmlEquals(expectedXml, contacts);
        }

        /// <summary>
        /// Select into BusinessEntity - but only specified attributes
        /// </summary>
        [Test]
        public void TestJoinSelectFromJoinedToBusinessEntity()
        {
            string expectedXml = @"
                <fetch mapping=""logical"">
                    <entity name=""contact"">
                        <attribute name=""fullname"" />
                        <link-entity name=""account"" from=""accountid"" to=""parentcustomerid"">
                            <attribute name=""name"" />
                        </link-entity>
                    </entity>
                </fetch>";
            var contacts = from c in provider.Linq<contact>()
                           join a in provider.Linq<account>()
                            on c.parentcustomerid.Value equals a.accountid.Value
                           select new contact { fullname = c.fullname, firstname = a.name };
            AssertXmlEquals(expectedXml, contacts);
        }

        /// <summary>
        /// steffana
        /// Select into BusinessEntity - but only specified attributes
        /// With join and where clause on main entity
        /// </summary>
        [Test]
        public void TestJoinSelectWhereToBusinessEntity()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><attribute name=\"fullname\" /><filter><condition attribute=\"fullname\" operator=\"eq\" value=\"Scott\" /></filter><link-entity name=\"account\" from=\"accountid\" to=\"parentcustomerid\" /></entity></fetch>";
            var contacts = from c in provider.Linq<contact>()
                           join a in provider.Linq<account>()
                            on c.parentcustomerid.Value equals a.accountid.Value
                           where c.fullname == "Scott"
                           select new contact { fullname = c.fullname };
            AssertXmlEquals(expectedXml, contacts);
        }

        /// <summary>
        /// Select into BusinessEntity - but only specified attributes
        /// With join and where clause on main entity - selecting from joined entity
        /// </summary>
        [Test]
        public void TestJoinSelectOnJoinedWhereToBusinessEntity()
        {
            string expectedXml = @"
                <fetch mapping=""logical"">
                    <entity name=""contact"">
                        <attribute name=""fullname"" />
                        <filter><condition attribute=""fullname"" operator=""eq"" value=""Scott"" /></filter>
                        <link-entity name=""account"" from=""accountid"" to=""parentcustomerid"">
                            <attribute name=""name"" />
                        </link-entity>
                    </entity>
                </fetch>";
            var contacts = from c in provider.Linq<contact>()
                           join a in provider.Linq<account>()
                            on c.parentcustomerid.Value equals a.accountid.Value
                           where c.fullname == "Scott"
                           select new contact { fullname = c.fullname, firstname = a.name };
            AssertXmlEquals(expectedXml, contacts);
        }

        /// <summary>
        /// steffana
        /// Select into BusinessEntity - but only specified attributes
        /// With join and where clause on joined entity
        /// </summary>
        [Test]
        public void TestJoinSelectWhereOnJoinedToBusinessEntity()
        {
            string expectedXml = @"
                <fetch mapping=""logical"">
                    <entity name=""contact"">
                        <attribute name=""fullname"" />
                        <link-entity name=""account"" from=""accountid"" to=""parentcustomerid"">
                            <filter>
                                <condition attribute=""name"" operator=""eq"" value=""Scott"" />
                            </filter>
                        </link-entity>
                    </entity>
                </fetch>";
            var contacts = from c in provider.Linq<contact>()
                           join a in provider.Linq<account>()
                            on c.parentcustomerid.Value equals a.accountid.Value
                           where a.name == "Scott"
                           select new contact { fullname = c.fullname };
            AssertXmlEquals(expectedXml, contacts);
        }

        /// <summary>
        /// steffana
        /// Constructing an In-Clause using <see cref="List{T}.Contains"/>.
        /// </summary>
        [Test]
        public void TestWhereInClause()
        {
            string expectedXml = "<fetch mapping=\"logical\"><entity name=\"contact\"><attribute name=\"fullname\" /><filter><condition attribute=\"firstname\" operator=\"in\"><value>scott</value><value>john</value></condition></filter></entity></fetch>";
            List<String> names = new List<String>() { "scott", "john" };
            var contactsWithNames = from c in provider.Linq<contact>()
                                    where names.Contains(c.firstname)
                                    select new contact { fullname = c.fullname };
            AssertXmlEquals(expectedXml, contactsWithNames);
        }

        /// <summary>
        /// steffana
        /// Constructing an In-Clause using <see cref="List{T}.Contains"/> - with join.
        /// </summary>
        [Test]
        public void TestWhereInClauseJoin()
        {
            string expectedXml = @"
                <fetch mapping=""logical"">
                    <entity name=""contact"">
                        <attribute name=""fullname"" />
                        <filter>
                            <condition attribute=""firstname"" operator=""in"">
                                <value>scott</value>
                                <value>john</value>
                            </condition>
                        </filter>
                        <link-entity name=""account"" from=""accountid"" to=""parentcustomerid"" />
                    </entity>
                </fetch>";
            List<String> names = new List<String>() { "scott", "john" };
            var contactsWithNames = from c in provider.Linq<contact>()
                                    join a in provider.Linq<account>()
                                        on c.parentcustomerid.Value equals a.accountid.Value
                                    where names.Contains(c.firstname)
                                    select new contact { fullname = c.fullname };
            AssertXmlEquals(expectedXml, contactsWithNames);
        }

        /// <summary>
        /// The provider should not blindly use the last Property as the attribute so that we can use things like Value
        /// </summary>
        [Test]
        public void TestValueProperty()
        {
            string expectedXml = @"
                <fetch mapping=""logical"">
                  <entity name=""product"">
                    <attribute name=""producttypecode"" />
                  </entity>
                </fetch>";
            var products = from p in provider.Linq<product>()
                           select new { p.producttypecode.Value };
            AssertXmlEquals(expectedXml, products);
        }

        /// <summary>
        /// Test attribute renaming so that we can join objects that have properties with identical names
        /// </summary>
        [Test]
        public void TestJoinWithAttributeRenamingAndNoAttributesOnMainEntity()
        {
            string expectedXml = @"
                <fetch mapping=""logical"">
                  <entity name=""productpricelevel"">
                    <link-entity name=""product"" from=""productid"" to=""productid"">
                      <attribute name=""name"" />
                      <attribute name=""productid"" />
                      <attribute name=""producttypecode"" />
                      <attribute name=""productnumber"" />
                      <filter>
                        <condition attribute=""statecode"" operator=""eq"" value=""0"" />
                      </filter>
                    </link-entity>
                    <link-entity name=""uom"" from=""uomid"" to=""uomid"">
                      <attribute name=""name"" />
                      <attribute name=""uomid"" />
                      <filter>
                        <condition attribute=""name"" operator=""ne"" value=""Transfer Price"" />
                      </filter>
                    </link-entity>
                  </entity>
                </fetch>
                ";

            var pricelevels = from pl in provider.Linq<productpricelevel>()
                              join pr in provider.Linq<product>() on pl.productid.Value equals pr.productid.Value
                              join uom in provider.Linq<uom>() on pl.uomid.Value equals uom.uomid.Value
                              where pr.statecode.Value == 0 && uom.name != "Transfer Price"
                              select new { pr.name, pr.productid, pr.producttypecode, pr.productnumber, uomname = uom.name, uom.uomid };

            AssertXmlEquals(expectedXml, pricelevels);
        }

        /// <summary>
        /// Test Selecting joined entities with all-attributes
        /// </summary>
        [Test]
        public void TestJoinSelectWithAllAttributes()
        {
            string expectedXml = @"
                <fetch mapping=""logical"">
                  <entity name=""productpricelevel"">
                    <all-attributes />
                    <link-entity name=""product"" from=""productid"" to=""productid"">
                        <all-attributes />
                    </link-entity>
                  </entity>
                </fetch>
                ";

            var pricelevels = from pl in provider.Linq<productpricelevel>()
                              join pr in provider.Linq<product>() on pl.productid.Value equals pr.productid.Value
                              select new { pl, pr };

            AssertXmlEquals(expectedXml, pricelevels);
        }

        /// <summary>
        /// BinaryExpression in select should not affect fetch conditions
        /// </summary>
        [Test]
        public void TestBinaryExpressionInSelect()
        {
            string expectedXml = @"
                <fetch mapping=""logical"">
                  <entity name=""contact"">
                    <attribute name=""firstname"" />
                  </entity>
                </fetch>
                ";
            var contacts = from c in provider.Linq<contact>()
                           select new { name = (c.firstname == null ? "Default" : c.firstname) };
            AssertXmlEquals(expectedXml, contacts);
        }

        /// <summary>
        ///  Deep join levels so that the recursive code in StunnwareExtensions gets tested.
        /// </summary>
        [Test]
        public void TestDeepJoinWithRenameSelect()
        {
            string expectedXml = @"
                <fetch mapping=""logical"">
                  <entity name=""salesorderdetail"">
                    <attribute name=""salesorderdetailid"" />
                    <attribute name=""productid"" />
                    <link-entity name=""salesorder"" from=""salesorderid"" to=""salesorderid"">
                        <link-entity name=""pricelevel"" from=""pricelevelid"" to=""pricelevelid"">
                            <link-entity name=""productpricelevel"" from=""pricelevelid"" to=""pricelevelid"">
                                <attribute name=""amount"" />
                            </link-entity>
                        </link-entity>
                    </link-entity>
                  </entity>
                </fetch>
                ";
            var items = from item in provider.Linq<salesorderdetail>()
                        join cosla in provider.Linq<salesorder>() on item.salesorderid.Value equals cosla.salesorderid.Value
                        join pl in provider.Linq<pricelevel>() on cosla.pricelevelid.Value equals pl.pricelevelid.Value
                        join ppl in provider.Linq<productpricelevel>() on pl.pricelevelid.Value equals ppl.pricelevelid.Value
                        select new
                        {
                            guid = item.salesorderdetailid.Value,
                            name = item.productid.name,
                            defaultprice = ppl.amount.Value
                        };
            AssertXmlEquals(expectedXml, items);
        }
    }
}
